import { color } from '../../../core/color.js';
import { Command } from '../../utils/cli-handler.js';
import { generateManifest } from '../../utils/manifest.js';
import { logger } from '../../../core/logger.js';
import { getProjectSize, printBuildSummary } from '../../utils/build-summary.js';
import { buildAsync } from '../dev.js';
import fs from 'node:fs/promises';
import path from 'node:path';
import { Env } from '../../../core/env.js';
import { Mode, setMode } from '../../../core/mode.js';
import { loadConfig, loadConfigPath } from '../../../core/config.js';
import { hasProperties } from '../../utils/utils.js';
import Watcher from '../../utils/watcher.js';
import { buildPublicDirectory } from '../../utils/public.js';

const command = new Command("plugin").description("Builds your plugin for distribution.").option("-d", "--dev", "build for development").option("-m", "--mode", "specify the mode(s) to run in (dev, beta, prod, etc...)").option("-s", "--silent", "do not print anything").option("-v", "--verbose", "print more information for debugging").option("-w", "--watch", "watch for changes and rebuild").option("-h", "--help", "Shows the available command options").handler(pluginAction);
var plugin_default = command;
async function pluginAction(_args, options) {
  logger({
    enabled: !options.silent,
    level: options.verbose ? "debug" : options.dev ? "warn" : "info"
  }).info(`Building Robo plugin...`);
  logger.debug("CLI options:", options);
  logger.debug(`Current working directory:`, process.cwd());
  if (!process.env.NODE_ENV) {
    process.env.NODE_ENV = options.dev ? "development" : "production";
  }
  const defaultMode = Mode.get();
  await Env.load({ mode: defaultMode });
  const { shardModes } = setMode(options.mode);
  if (shardModes) {
    logger.error(`Mode sharding is not available for builds.`);
    process.exit(1);
  }
  const startTime = Date.now();
  const config = await loadConfig("robo", true);
  const { Compiler } = await import('../../utils/compiler.js');
  const compileTime = await Compiler.buildCode({
    excludePaths: config.excludePaths?.map((p) => p.replaceAll("/", path.sep)),
    plugin: true
  });
  logger.debug(`Compiled in ${compileTime}ms`);
  await Compiler.buildSeed();
  const manifestTime = Date.now();
  const manifest = await generateManifest({ commands: {}, context: {}, events: {} }, "plugin");
  logger.debug(`Generated manifest in ${Date.now() - manifestTime}ms`);
  if (!options.dev) {
    await buildPublicDirectory();
    const sizeStartTime = Date.now();
    const totalSize = await getProjectSize(process.cwd());
    logger.debug(`Computed plugin size in ${Date.now() - sizeStartTime}ms`);
    printBuildSummary(manifest, totalSize, startTime, true);
  }
  if (options.watch || options.dev) {
    const watchFile = path.join(process.cwd(), ".robo", "watch.mjs");
    const watchContents = `export default ${JSON.stringify(
      {
        updatedAt: Date.now()
      },
      null,
      "	"
    )}`;
    await fs.writeFile(watchFile, watchContents);
  } else {
    const watchFile = path.join(process.cwd(), ".robo", "watch.mjs");
    try {
      const exists = await fs.stat(watchFile);
      if (exists.isFile()) {
        await fs.rm(watchFile);
      }
    } catch (e) {
      if (hasProperties(e, ["code"]) && e.code !== "ENOENT") {
        logger.warn(`Failed to clean up watch file! Please delete it manually at ${watchFile}`);
      }
    }
  }
  if (options.watch) {
    const watchedPaths = ["src"];
    const configPath = await loadConfigPath();
    let configRelative;
    if (configPath) {
      configRelative = path.relative(process.cwd(), configPath);
      watchedPaths.push(configRelative);
    }
    const watcher = new Watcher(watchedPaths, {
      exclude: ["node_modules", ".git"]
    });
    let isUpdating = false;
    logger.ready(`Watching for changes...`);
    watcher.start(async (changes) => {
      logger.debug(`Watcher events: ${changes.map((change) => change.changeType).join(", ")}`);
      if (isUpdating) {
        return logger.debug(`Already building, skipping...`);
      }
      isUpdating = true;
      try {
        const configChange = changes.find((change) => change.filePath === configRelative);
        if (configChange) {
          const fileName = configChange.filePath.split("/").pop();
          logger.wait(`${color.bold(fileName)} file was updated. Rebuilding to apply configuration...`);
        } else {
          logger.wait(`Change detected. Rebuilding plugin...`);
        }
        const time = Date.now();
        await buildAsync("robo build plugin --dev", config, options?.verbose, []);
        logger.ready(`Successfully rebuilt in ${Date.now() - time}ms`);
      } finally {
        isUpdating = false;
      }
    });
  } else if (!options.dev) {
    process.exit(0);
  }
}

export { plugin_default as default };
